package cn.b.sky.common.file;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFPicture;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

public class Excel {

  private HSSFWorkbook workBook;

  private HSSFSheet sheet;

  private JSONObject imageMap;

  private JSONObject tableMap;

  //记录已占区域的 坐标，左上角(col0,row0)，右下角(col1,row1)
  private int x0 = 0;

  private int y0 = 0;

  private int x1 = 0;

  private int y1 = 0;

  private static final int ROWINTERVAL = 2;//设置Model之间的行间隔

  private static final int COLINTERVAL = 1;//设置Model之间的列间隔

  LinkedList<Square> squares = new LinkedList<Square>();

  List<HSSFPicture> pictures = new ArrayList<HSSFPicture>();

  private static final String RIGHT = "right";

  private static final String NEWLINE = "newLine";

  private static final String BELOW = "below";

  /**
   * 
   * <strong>Description : </strong>默认创建HSSFWorkbook和Sheet<br> 
   * <strong>Create on : 2016年3月25日 下午3:58:48<br></strong>
   * <p>
   * @throws 
   * @author zhanghongjiang<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   * <strong>修改历史:</strong><br>
   * 修改人 | 修改日期 | 修改描述<br>
   * -------------------------------------------<br>
   * <br>
   * <br>
   */
  public Excel() {
    this.workBook = new HSSFWorkbook();
    this.sheet = this.workBook.createSheet();
  }

  public Excel(HSSFWorkbook workwork, HSSFSheet sheet) {
    this.workBook = workwork;
    this.sheet = sheet;
  }

  /**
   * 
   * <strong>Title : addToNextLine<br></strong>
   * <strong>Description : </strong>换行从第一列开始新加组件<br> 
   * <strong>Create on : 2016年3月24日 上午8:58:57<br></strong>
   * <p>
   * @param m
   * void
   * @throws 
   * @author zhanghongjiang<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   * <strong>修改历史:</strong><br>
   * 修改人 | 修改日期 | 修改描述<br>
   * -------------------------------------------<br>
   * <br>
   * <br>
   */
  public void addToNextLine(ExcelModel m) {
    x0 = 0;
    y0 = y1;

    Point end = null;
    Point start = null;
    if (y0 == 0) {
      start = new Point(x0, y0);
      end = addExcelModel(m, start);
    } else {
      start = new Point(x0, y0 + ROWINTERVAL);
      end = addExcelModel(m, start);
    }
    x1 = end.getCol();
    y1 = end.getRow();
    squares.add(new Square(start.col, start.row, end.col, end.row));
  }

  /**
   * 
   * <strong>Title : addToBelow<br></strong>
   * <strong>Description : </strong>把当前组件添加到上一组件的正下方<br> 
   * <strong>Create on : 2016年3月24日 上午8:59:31<br></strong>
   * <p>
   * @param m
   * void
   * @throws 
   * @author zhanghongjiang<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   * <strong>修改历史:</strong><br>
   * 修改人 | 修改日期 | 修改描述<br>
   * -------------------------------------------<br>
   * <br>
   * <br>
   */
  public void addToBelow(ExcelModel m) {
    Point end = null;
    Point start = null;
    Square last = squares.peekLast();
    if (last != null) {
      start = new Point(last.x0, last.y1 + ROWINTERVAL);
    } else {
      start = new Point(x0, y0);
    }
    end = addExcelModel(m, start);
    if (x1 < end.getCol()) {
      x1 = end.getCol();
    }
    if (y1 < end.getRow()) {
      y1 = end.getRow();
    }
    squares.add(new Square(start.col, start.row, end.col, end.row));
  }

  /**
   * 
   * <strong>Title : addToRight<br></strong>
   * <strong>Description : </strong>继续往右添加组件<br> 
   * <strong>Create on : 2016年3月24日 上午8:59:58<br></strong>
   * <p>
   * @param m
   * void
   * @throws 
   * @author zhanghongjiang<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   * <strong>修改历史:</strong><br>
   * 修改人 | 修改日期 | 修改描述<br>
   * -------------------------------------------<br>
   * <br>
   * <br>
   */
  public void addToRight(ExcelModel m) {
    Point start = new Point(x1 + COLINTERVAL, y0);
    Point end = addExcelModel(m, start);
    if (x1 < end.getCol()) {
      x1 = end.getCol();
    }
    if (y1 < end.getRow()) {
      y1 = end.getRow();
    }
    squares.add(new Square(start.col, start.row, end.col, end.row));
  }

  public void addExcelModel(ExcelModel m, int col, int row) {
    Point start = new Point(col, row);
    addExcelModel(m, start);
  }

  private Point addExcelModel(ExcelModel m, Point start) {
    if (start == null) {
      start = new Point(0, 0);
    }
    if (m == null) {
      return new Point(x1, y1);
    }
    m.setExcel(this);

    return m.insert(start);
  }

  public void addExcelModel(ExcelModel m) {
    addToNextLine(m);
  }

  /** 
  * @return workwork
  */
  public HSSFWorkbook getWorkwork() {
    return workBook;
  }

  /** 
  * @param workwork 要设置的 workwork
  */
  public void setWorkwork(HSSFWorkbook workwork) {
    this.workBook = workwork;
  }

  /** 
  * @return sheet
  */
  public HSSFSheet getSheet() {
    return sheet;
  }

  /** 
  * @param sheet 要设置的 sheet
  */
  public void setSheet(HSSFSheet sheet) {
    this.sheet = sheet;
    //重置到原始坐标
    x0 = 0;
    y0 = 0;
    x1 = 0;
    y1 = 0;
  }

  public void doExport(HttpServletResponse response, String title) throws IOException {
    //重新调整图片大小
    for (HSSFPicture p : this.pictures) {
      p.resize();
    }
    response.setHeader("Content-disposition", "attachment; filename="
        + new String(title.getBytes("gb2312"), "iso8859-1") + ".xls");// 设定输出文件头   
    response.setContentType("application/msexcel");// 定义输出类型 
    this.getWorkwork().write(response.getOutputStream());
  }

  public void autoAddModel(String arrangement, Map<String, List<Map<String, Object>>> tableListMap) {
    if (StringUtils.isBlank(arrangement)) {
      return;
    }
    String[] models = arrangement.split(";");
    //匹配坐标 (x,y)
    Pattern p1 = Pattern.compile("^\\(\\d+,\\d+\\)$");
    //匹配纯字母
    Pattern p2 = Pattern.compile("^[a-zA-Z]+$");
    for (String model : models) {
      String[] attr = model.split(":");
      if (attr.length >= ROWINTERVAL) {
        String modelName = attr[0];
        String modelPosition = attr[1];
        ExcelModel m = null;
        if (this.containsImage(modelName)) {
          m = new ImageModel(this.getImage(modelName));
        } else if (tableListMap != null && this.containsTable(modelName)) {
          m = new GridModel(this.getTable(modelName), tableListMap.get(modelName));
        }
        if (p1.matcher(modelPosition).find()) {
          String[] coordinates = modelPosition.replaceAll("\\(|\\)", "").split(",");
          int x = Integer.parseInt(coordinates[0]);
          int y = Integer.parseInt(coordinates[1]);
          this.addExcelModel(m, x, y);
        } else if (p2.matcher(modelPosition).find()) {
          addByPositionName(modelPosition, m);
        }
      }
    }
  }

  private void addByPositionName(String position, ExcelModel model) {
    if (StringUtils.isBlank(position) || model == null) {
      return;
    }
    if (position.equalsIgnoreCase(RIGHT)) {
      this.addToRight(model);
    } else if (position.equalsIgnoreCase(BELOW)) {
      this.addToBelow(model);
    } else if (position.equalsIgnoreCase(NEWLINE)) {
      this.addToNextLine(model);
    }
  }

  /** 
  * @return imgData
  */
  public String getImage(String key) {
    return imageMap != null ? (String) imageMap.get(key) : null;
  }

  /** 
   * @return imgData
   */
  public boolean containsImage(String key) {
    return imageMap != null ? imageMap.containsKey(key) : false;
  }

  /** 
  * @param imageMap
  */
  public void setImageMap(String imageMap) {

    this.imageMap = JSON.parseObject(imageMap);

  }

  /** 
  * @return tableMap
  */
  public List<Map> getTable(String tableId) {
    return tableMap != null ? (List<Map>) tableMap.get(tableId) : null;
  }

  /** 
   * @return boolean
   */
  public boolean containsTable(String tableId) {
    return tableMap != null ? tableMap.containsKey(tableId) : false;
  }

  /** 
  * @param tableMap 要设置的 tableMap
  */
  public void setTableMap(String tableMap) {
    this.tableMap = JSON.parseObject(tableMap);
  }

  /** 
  * @return pictures
  */
  public List<HSSFPicture> getPictures() {
    return pictures;
  }

  /** 
  * @param pictures 要设置的 pictures
  */
  public void setPictures(List<HSSFPicture> pictures) {
    this.pictures = pictures;
  }

}
